/****************************************************************
 * Programa que efetua o pre-processamento de uma Base de Dados	*
 * gerando a estrutura secundaria e caracteristicas extraidas de*
 * suas sequencias. A biblioteca VIENA para auxiliar na geração	*
 * da estrutura secundária.										*
 * 																*
 * Autora: Cristina Teixeira de Oliveira						*
 * e-mail: cto@icmc.usp.br										*
 * *************************************************************/
 
/****************************************************************
 * Ao chamar a função, devem ser passados dois arquivos:		*
 * Ex.: estSecundaria arquivo1 arquivo2							*
 * Onde, arquivo1 é a base de dados que contém as sequencias a 	*
 * serem geradas o arquivo2 contendo as estruturas secundarias e*
 * características extraídas dessas esruturas geradas. 			*
 * **************************************************************/ 
 
#include <stdio.h> 
#include <math.h>
#include <string.h>
#include <stdlib.h>


//#include <exception>

#include "/home/cris/VIENA/ViennaRNA-1.6.4/H/fold.h"
#include "/home/cris/VIENA/ViennaRNA-1.6.4/H/fold_vars.h"

//#define TAM_MAX_SEQ 1000 
#define _GNU_SOURCE
#define MAX_SUBCADEIAS 1000

/****************************************************************
 * A funcao geraEstSecundaria(char *linha, char *estrutura) gera*
 * a estrutura secundaria de "linha" em "estrutura".			*
 * 																*
 * E esta funcao que utiliza a biblioteca VIENA.				*
 * *************************************************************/
char *geraEstSecundaria(char *linha) {
	char *struct1;
 	int tamMaxSeq;

	// Variaveis utilizadas ao chamar funções da biblioteca VIENA.	 	
 	float e1;
	//printf("Linha em geraEstSecundaria: %s Tamanho: %i", linha, strlen(linha));
	// VIENA: Definição do parametro temperatura.  
 	// fold at 30C instead of the default 37C
 	temperature = 50;
							
	tamMaxSeq = strlen(linha);

	// Alocando espaço para gerar estrutura.
	// espaço alocado deve ser pelo menos o tamanho da sequencia.
	/* allocate memory for fold(), could be skipped */
	initialize_fold(tamMaxSeq);
	/* allocate memory for structure and fold */
	struct1 = (char* ) space(sizeof(char)*(tamMaxSeq+1));
	
	// Gerando a estrutura da sequencia.
	e1 =  fold(linha, struct1);
	
	// Liverando espaco utilizado no dobramento, em fold().
	/* free arrays used in fold() */
	free_arrays(); 
	//printf("\nStruct1: %s\n", struct1);
	
	return (struct1);
	     	
}

int inicializaVetorSubcadeia(int *filtroSubcadeia){
	int i;
	
	for (i=0; i<MAX_SUBCADEIAS; i++){
		filtroSubcadeia[i]=0;
	}
	
	return 1;
}

unsigned long long int calculaFiltroSubcadeia(int *filtroSubcadeia){
	int i;
	long int total = 0;
	
	for (i=0; i<MAX_SUBCADEIAS; i++){
		// Usando o cálculo polinomial: x + y2 + z3 +...		
		//total = (unsigned long long int)(pow(filtroSubcadeia[i],(i+1))+total);
		// Usando o cálculo linear: x + 2y + 3z + ...
		total = (unsigned long long int)(filtroSubcadeia[i]*(i+1)+total);
		/*if (filtroSubcadeia[i] != 0){
			printf("\tIndice: %d Total: %d", i, filtroSubcadeia[i] );		 
		}*/
	}
	return total;
}


/****************************************************************
 * A funcao extraiSubCadeias(char *estrutura, file *arquivo)	*
 * grava em arquivo os talos/subcadeias encontradas em			*
 * estrutura.													*
 * 																*
 * As subcadeias extraidas nesta função são cadeias 			*
 * independentes, começando e finalizando com um pereamento.	*	
 * *************************************************************/
char *extraiSubCadeias(char *estrutura, int *contSubCadeias){
	int tamSeq = strlen(estrutura);
	char talo[tamSeq];
	char *subcadeias;
	int cont, inicio, tamSubCadeias, i, j;
	int contPareado, contNaoPar;
	unsigned long long int total;
	int filtroSubcadeia[MAX_SUBCADEIAS];
	int tamFiltroSubcadeia;	
	
	cont = 0;
	contPareado = 0;
	contNaoPar = 0;
	*contSubCadeias = 0;
	tamSubCadeias = 0;
	tamFiltroSubcadeia = 0;
	
	int tamMaxSeq = strlen(estrutura);	
	subcadeias = (char* ) space(sizeof(char)*(tamMaxSeq*3));
	
	if (inicializaVetorSubcadeia(filtroSubcadeia) != 1) printf("\nErro na inicialização do vetor!\n");
	
	for (i=0; i<tamSeq; i++){

		// Extrai os Intervalos entre as subsequencias
		if ((cont==0)&&(estrutura[i]=='.')){ //-> Contabiliza apenas os fora da subcadeia
		//if (estrutura[i]=='.'){
			contNaoPar++;
		}		
		else if (estrutura[i]=='(') { 
			// Se o contador estava zerado deve-se guardar início da posição da subsequencia
			if (cont==0) inicio=i;
			// Armazena o numero de pareamentos em nivel
			filtroSubcadeia[cont]++;
			if ((cont+1)>tamFiltroSubcadeia) tamFiltroSubcadeia = cont +1;  
			cont++;
			contPareado++;						
		}
		else if (estrutura[i]==')') {
			cont-- ; 
			if (cont==0){
				(*contSubCadeias)++;
				// Guardar subcadeia encontrada
				// Da posicao "inicial" ate "i"
				// concatenar subsequencia com o intervalo encontrado 
				
				//Separando subcadeias
				//Decidir qual vai ser o separador
				
				if (tamSubCadeias > 0) {
					subcadeias[tamSubCadeias] = '\t';
					tamSubCadeias++;
				}	
				
				// Copiando subcadeia
				for(j=inicio; j<=i; j++){								
    				subcadeias[tamSubCadeias] =  estrutura[j];
    				tamSubCadeias++;
  				}
			}			
		}						
	}			
	subcadeias[tamSubCadeias] =  '\0';	
	total = calculaFiltroSubcadeia(filtroSubcadeia);
	sprintf( subcadeias, "%s\t%d", subcadeias, contPareado);	
	sprintf( subcadeias, "%s\t%d\t%lu", subcadeias, contNaoPar, total);
	
	//printf("\nSubcadeia1111: %s", subcadeias);
	
	sprintf( subcadeias, "%s\t%d", subcadeias, tamFiltroSubcadeia);
	//printf("\n Tamanho de Filtro de Subcadeias: %d", tamFiltroSubcadeia);
	
	//printf("\nSubcadeia2222: %s", subcadeias);
	
	for (j=0; j<tamFiltroSubcadeia; j++){
		//printf("\n Filtro[%d]: %d", j, filtroSubcadeia[j]);
		sprintf(subcadeias, "%s\t%d", subcadeias, filtroSubcadeia[j]);
	}
	printf("\nSubcadeia: %s", subcadeias);
			
	return (subcadeias);
}
     

int main(int argc, char *argv[]) {
	// verificando quantidade de parametros passados.
	if (argc <= 1){
		printf("\nParâmetro Incorreto! --- %d\n", argc);	
	}else{
		printf("%s", argv[1]);		
	 	FILE *arquivo, *baseDados;	// Arquivos de Entrada e Saida.
	 	size_t len = 0; // valor arbitrário para usar getLine
	 	
	 	char *linha = malloc(len);	// linha para leitura de sequencia.
	 	char *estrutura = malloc(len);// linha para saida da estrutura secundaria.
	 	char *subcadeias = malloc(2*len);
	 	int contSubCadeias;
	 	
	 	//Abrindo arquivo de leitura: base de entrada.
	 	if ((arquivo = fopen(argv[1], "r")) == NULL){
	 		printf("ERRO ao abrir o arquivo de leitura!\n");
	 		return(0);
	 	}
	 	
	 	//Abrindo arquivo de escrita: base processada.	 	
	 	if ((baseDados = fopen(argv[2], "w")) == NULL){
	 		printf("ERRO ao abrir o arquivo de escrita!\n");
	 		return(0);
	 	}
	 		 	
		//while ((fscanf(arquivo, "%[^\n]", linha)) != EOF){
		while (getline(&linha, &len, arquivo) > 0){
			// Verificando se a linha refere-se a descrção FASTA 	
			if (linha[0] == '>'){
				//Salva descrição				
				printf("\n\nDesc = %s ", linha);
				linha[strlen(linha)-1] = '\t';
				fprintf(baseDados, "%s", linha);
				
			} else{
				printf("\nLinha = %s ", linha);			
				// Gerar estrutura secundaria.
				estrutura = geraEstSecundaria(linha);
				printf("\nEstrutura: %s", estrutura);
				
				// Extrair subcadeias da estrutura secundaria.
				subcadeias = extraiSubCadeias(estrutura, &contSubCadeias);
				printf("\nSubcadeias: %s", subcadeias);
				linha[strlen(linha)-1] = '\t';
				fprintf(baseDados, "%s%s\t%d\t%s\n", linha, estrutura, contSubCadeias, subcadeias);			
			}				 			
			
			//fgetc(arquivo);			
			
			//printf("\nResultado: %s\t%s\t%d\t%s\n", linha, estrutura, contSubCadeias, subcadeias);
			
		}
      	
      	fclose(arquivo);
      	fclose(baseDados);
	 	   
		printf("\nFIM!\n");
		//return(1);
	}	
}
